//    Copyright (C) Kherty.  All rights reserved.
#region

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Core.Serialization;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Parsing;

#endregion

namespace OpenLS.Spreadsheet
{
    public class CellIsFormattingRule : StandardConditionalFormattingRule
    {
        public ConditionalFormattingOperator Operator { get; set; }

        internal override ConditionalFormattingType Type
        {
            get { return ConditionalFormattingType.CellIs; }
        }

        protected override void ReadInner2(ReadContext context)
        {
            Operator = context.GetEnum<ConditionalFormattingOperator>("operator");
        }

        internal override void WriteInner2(WriteContext context)
        {
            context.SetEnum("operator", Operator);
        }

        internal override bool Apply(Cell cell)
        {
            return ApplyStyle(cell, AppliesTo(cell));
        }

        private bool AppliesTo(Cell cell)
        {
            var o = Operator;
            switch (o)
            {
                case ConditionalFormattingOperator.GreaterThan:
                case ConditionalFormattingOperator.GreaterThanOrEqual:
                case ConditionalFormattingOperator.LessThan:
                case ConditionalFormattingOperator.LessThanOrEqual:
                    return appliesToAsDouble(cell);
                case ConditionalFormattingOperator.Equal:
                case ConditionalFormattingOperator.NotEqual:
                    return appliesToAsObject(cell);
                case ConditionalFormattingOperator.Between:
                case ConditionalFormattingOperator.NotBetween:
                    return appliesToAsDouble(cell);

                case ConditionalFormattingOperator.BeginsWith:
                case ConditionalFormattingOperator.ContainsText:
                case ConditionalFormattingOperator.EndsWith:
                case ConditionalFormattingOperator.NotContains:
                    return AppliesToAsString(cell);
                default:
                    throw new NotSupportedException();
            }
        }

        private bool AppliesToAsString(Cell cell)
        {
            var o = cell.Value;
            if (o == null)
                return false;
            var s = o.ToString();

            var formulaValue = FormulaObject1.GetValue() as string;//\\ base.GetFormulaValue(Formula1, cell) as string;
            if (formulaValue == null)
                return false;
            switch (Operator)
            {
                case ConditionalFormattingOperator.ContainsText:
                    return s.Contains(formulaValue);
                case ConditionalFormattingOperator.BeginsWith:
                    return s.StartsWith(formulaValue);
                case ConditionalFormattingOperator.EndsWith:
                    return s.EndsWith(formulaValue);
                case ConditionalFormattingOperator.NotContains:
                    return !s.Contains(formulaValue);
                default:
                    throw new NotSupportedException();
            }
        }

        private bool appliesToAsObject(Cell cell)
        {
            var v = cell.Value;
            var comparison = FormulaObject1.CompareValueTo(v, cell.Worksheet.Workbook);
            switch (Operator)
            {
                case ConditionalFormattingOperator.Equal:
                    return comparison == CellFormulaBase.ComparisonResult.Equal;
                    case ConditionalFormattingOperator.NotEqual:
                    return comparison == CellFormulaBase.ComparisonResult.NotEqual;
            }
            // Contract.Assert(false);
            throw new NotSupportedException();
            return false;
        }

        private bool appliesToAsDouble(Cell cell)
        {
            var comparison = FormulaObject1.CompareValueTo(cell.Value, cell.Worksheet.Workbook);
            switch (Operator)
            {
                case ConditionalFormattingOperator.GreaterThan:
                    return comparison == CellFormulaBase.ComparisonResult.LessThan;
                    case ConditionalFormattingOperator.Equal:
                    return comparison == CellFormulaBase.ComparisonResult.Equal;
                    case ConditionalFormattingOperator.GreaterThanOrEqual:
                    return comparison == CellFormulaBase.ComparisonResult.Equal ||
                           comparison == CellFormulaBase.ComparisonResult.LessThan;
                    case ConditionalFormattingOperator.LessThan:
                    return comparison == CellFormulaBase.ComparisonResult.GreaterThan;
                    case ConditionalFormattingOperator.LessThanOrEqual:
                    return comparison == CellFormulaBase.ComparisonResult.GreaterThan ||
                           comparison == CellFormulaBase.ComparisonResult.NotEqual;
                    case ConditionalFormattingOperator.NotEqual:
                    {
                        switch (comparison)
                        {
                            case CellFormulaBase.ComparisonResult.GreaterThan:
                                case CellFormulaBase.ComparisonResult.LessThan:
                                case CellFormulaBase.ComparisonResult.NotEqual:
                                return true;
                            default:
                                return false;
                        }
                    }
                    case ConditionalFormattingOperator.Between:
                    {
                        if (comparison == CellFormulaBase.ComparisonResult.GreaterThan || comparison == CellFormulaBase.ComparisonResult.Equal)
                        {
                            var comparison2 = FormulaObject2.CompareValueTo(cell.Value, cell.Worksheet.Workbook);
                            return comparison2 == CellFormulaBase.ComparisonResult.Equal ||
                                   comparison2 == CellFormulaBase.ComparisonResult.LessThan;
                        }
                        return false;

                    }
                    case ConditionalFormattingOperator.NotBetween:
                    {
                        if (comparison == CellFormulaBase.ComparisonResult.LessThan || comparison == CellFormulaBase.ComparisonResult.NotEqual)
                        {
                            var comparison2 = FormulaObject2.CompareValueTo(cell.Value, cell.Worksheet.Workbook);
                            return comparison2 == CellFormulaBase.ComparisonResult.NotEqual ||
                                   comparison2 == CellFormulaBase.ComparisonResult.GreaterThan;
                        }
                        return false;
                          
                    }
                default: throw new NotImplementedException();
            }
            
        }
    }
}